import java.util.*;

public class MasterController
{
	private Area area;
	private Place playerPlace;
	private Player player;
	private Scanner sc;

	public MasterController() {
		int adjRand = (int)(Math.random()*GameUtils.worldAdjectives.length);
		int nounRand = (int)(Math.random()*GameUtils.worldNouns.length);
		String name = GameUtils.worldAdjectives[adjRand] + " " + GameUtils.worldNouns[nounRand];
		player = new Player("player", "player descrip", 100, new ArrayList<Entity>());
		area = new Area(name, "area descrip", new ArrayList<Place>());
		area.createPlaces(20);
		area.addPlayer(player);
	}

	public void run() {
		System.out.println("Welcome to the world of " + area.getName() + "!");
		System.out.println("Type help for commands.\n");
		sc = new Scanner(System.in);
		boolean wantsToQuit = false;
		
		while(!wantsToQuit) {
			String str = sc.nextLine().toLowerCase();
			ArrayList<String> parsedLine = parse(str);
			String command = parsedLine.get(0);
			
			playerPlace = area.playerPlace(player);
			
			if(command.equals("help")) {
				System.out.println(help());
			}
			
			else if(command.equals("quit")) {
				wantsToQuit = true;
			}
			
			else if(GameUtils.look.contains(command)){
				look(parsedLine);
			}
			
		/*	else if(GameUtils.use.contains(command)){
				if(size == GameUtils.useParams)
					System.out.println("You want to use " + parsedLine.get(1) + " on " + parsedLine.get(2));
				else
					System.out.println("Invalid parameters - proper use is " + GameUtils.useFormat);
			}*/
			
			else if(GameUtils.go.contains(command)) {
				go(parsedLine);
			}
					
			else if(command.equals("")) {
				System.out.println("Unknown command: \"" + command + "\"; you may have inserted an additional space.");
			} else {
				System.out.println("Unknown command: \"" + command + "\"");
			}
			
			System.out.println();
		}
	}
	
	/* 
	 * @return a separated ArrayList<String> containing
	 * each space-separated word within str 
	 */
	private ArrayList<String> parse(String str) {
		ArrayList<String> parsedLine = new ArrayList<String>();
		if(str.equals(""))
			return parsedLine;
		int startIndex = 0;
		for(int i=0; i<str.length(); i++) {
			if(i != str.length() - 1 && str.charAt(i) == ' ') {
				parsedLine.add(str.substring(startIndex,i));
				startIndex = i + 1;
			} else if(i == str.length() - 1) {
				parsedLine.add(str.substring(startIndex).trim());
			}
		}
		return parsedLine;
	}

	private String help() {
		return "Valid commands are:\nquit\n" + GameUtils.lookFormat + "\n" + GameUtils.useFormat + "\n" + GameUtils.goFormat;
	}
	
	/*
	 * if the command is just "look", "look around", or "look <CURRENT PLACE'S NAME>",
	 * it prints the Place description and exit directions.
	 * 
	 * otherwise, it prints the description of the specified Entity
	 * 
	 * double otherwise, if the "look" command was used wrong,
	 *  it tells the user they used they did so
	 */
	private void look(ArrayList<String> parsedLine) {
		int size = parsedLine.size();
		ArrayList<String> validDirections = area.getValidCardinalDirectionsFrom(playerPlace);
		
		if(size == 1 || parsedLine.get(1).equals("around") || parsedLine.get(1).equals(playerPlace.getName())) {
			System.out.println(playerPlace.look());										 
			printValidDirections(validDirections);
		}
		
		else if(size == GameUtils.lookParams) {
			Entity lookEnt = playerPlace.getEntityWithName(parsedLine.get(1));
			if(lookEnt == null) {
				System.out.println("Invalid entity specified: " + parsedLine.get(1));
			} else {
				System.out.println(lookEnt.look());
			}
		}
				
		else {
			System.out.println("Invalid parameters - proper use is " + GameUtils.lookFormat);
		}
	}
	
	/*
	 * if the command if correctly entered and in a valid direction,
	 * the player is put in newPlace after checking lock status.
	 * 
	 * otherwise, if the command is used incorrectly, an error is spat back.
	 * 
	 * double otherwise, if there's no place in that direction, another error is tossed.
	 */
	private void go(ArrayList<String> parsedLine) {
		int size = parsedLine.size();
		ArrayList<String> validDirections = area.getValidCardinalDirectionsFrom(playerPlace);
		
		if(size == GameUtils.goParams && GameUtils.directions.contains(parsedLine.get(1))
		   && validDirections.contains(parsedLine.get(1).toUpperCase())                 ) {
			Location currLoc = playerPlace.getLocation();
			Location newLoc = currLoc.getLocationInDirection(parsedLine.get(1).toUpperCase());
			Place newPlace = area.getPlaceAt(newLoc);
			if(playerPlace.isLocked()) {
				System.out.println("Your location, " + playerPlace.getName() + ", is locked!");
			} else if(newPlace.isLocked()) {
				System.out.println(newPlace.getName() + " is inaccessible!");
			} else {
				playerPlace.removeEntity(player);
				newPlace.addEntity(player);
				System.out.println(newPlace.look());
				validDirections = area.getValidCardinalDirectionsFrom(newPlace);
				printValidDirections(validDirections);
			}
		}
		
		else if(size != GameUtils.goParams || !GameUtils.directions.contains(parsedLine.get(1))) {
		 	System.out.println("Invalid parameters - proper use is " + GameUtils.goFormat);
		}
		
		else {
			System.out.println("Invalid direction specified: " + parsedLine.get(1));
		}
	}
	
	/*
	 * prints the valid exit directions from the player's current Place
	 */
	private void printValidDirections(ArrayList<String> validDirections) {
		System.out.print("Obvious exits are");
		for(int i=0; i < validDirections.size(); i++) {
			if(i == validDirections.size() - 1){
				System.out.print(" " + validDirections.get(i));
			} else {
				System.out.print(" " + validDirections.get(i) + " and");
			}
		}
		System.out.println(".");
	}

	public static void main(String[] args) {
		MasterController controller = new MasterController();
		controller.run();
	}
}
																										
																													
			